unit PendulumGraph;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, GraphScale, Math, Menus, graphSettingsGUI;
  
const
	TRANSCOLOR = $FF00FF;

type
  TGraphQuery = procedure (Sender : TObject) of object;
  TPendulumGraph = class(TPaintBox)
  private
    { Private declarations }
	
	//Layer bitmaps
	BufferBitmap : TBitmap; //Buffer
	CursorOverlayBitmap : TBitmap; //Cursor and Cursor Text
	AxisOverlayBitmap : TBitmap;//Axis and axis text
	DataOverlayBitmap : TBitmap; //Data points
	
	//Bitmap Depth
	_defaultPixelFormat : TPixelFormat;
	
	//Drawing properties
	_scale : TScale; // X and Y scales in pixels per unit
    _start : Real; // Time at y-origin
	_xMajorTicksPer : integer;
	_xMinorTicksPer : integer;
	_yMajorTicksPer : integer;
	_yMinorTicksPer : integer;
	//Colors
	_backgroundColor : TColor; //Background color (Background of graph)
	_foregroundColor : TColor; //Foreground color (Mainly for data)
	_AxisColor : TColor; //Axis color
	_cursorColor : TColor; //Cursor color
	
	//Pens
	_cursorWidth : integer; //Width of pen used to draw cursor
	_axisWidth : integer; //Width of pen used to draw each axis
	_majorTickWidth : integer; //Width of major axis ticks
	_minorTickWidth : integer; //Width of minor axis ticks
	
	//Points
	_axisOrigin : TPoint;
	
	//Ready
	_ready : boolean;
	
	_yAxisLabel: String; //Y Axis Label and Unit
	_xAxisLabel: String; //X Axis Label and Unit
	
	//Amplitude Autoscaling
	_autoScale : boolean;
	_maxAmplitude : Real;
	
	//Popup Menu
	_popupMenu : TPopupMenu;
	_popupMenuItems: array[1..10] of TMenuItem;
	
	//Preferences
	_displayAxes: boolean;
	_displayTicks : boolean;
	_displayScale : boolean;

        _thickerDots: boolean;
	
	//Settings Window
	_settingsWindow : TGraphSettings;
	
	//Whats this event handler
	whatsThis : TGraphQuery;

	
	//Procedures
	procedure _resetDrawingTools; //Set all drawing tools to default states
	
	procedure _readjustSizes; //Work out scaling and bitmap sizes
	
	procedure _AxisInitialise;
	

	procedure _drawCursor(x, y: integer); //Draw cursor at x, y
	
	//procedure _drawDatapoint(x, y: integer); //Draw a data point (pixel) at co-ordinates x,y
	
	//Menu handlers
	procedure _menuShowSettings(Sender : TObject);
	procedure _menuInitialise(Sender : TObject);
	procedure _menuResetXAxis(Sender : TObject);
	procedure _menuToggleAxes(Sender : TObject);
	procedure _menuToggleTicks(Sender : TObject);
	procedure _menuToggleScale(Sender : TObject);
        procedure _menuToggleDots(Sender : TObject);
	procedure _menuWhatsThis(Sender : TObject);
	
	
  protected
    { Protected declarations }
  public
    { Public declarations }
	constructor Create(AOwner: TComponent); override; //Override the constructer for initial settings
    destructor Destroy; override;
	procedure Paint; override; //Override the paint function to redraw our paintbox
	procedure Resize; override;
	procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
	
	//Show Settings
	procedure ShowSettings;

	
	procedure Initialise;
	procedure DrawPointWithColor(time, amplitude: real; color : TColor);
    procedure DrawPoint(time, amplitude: real);
	procedure SetScale(x, y : real);
	procedure SetOrigin(x, y : integer);
  
  published
    { Published declarations }
	//Auto Scale
	property AutoScale : boolean Read _autoScale Write _autoScale;
	//Pixel Formats
	property PixelFormat : TPixelFormat Read _defaultPixelFormat Write _defaultPixelFormat;
		
	//Colors
	property BackgroundColor : TColor Read _backgroundColor Write _backgroundColor;
	property ForegroundColor : TColor Read _foregroundColor Write _foregroundColor;
	property AxisColor : TColor Read _axisColor Write _axisColor;
	property CursorColor : TColor Read _cursorColor Write _cursorColor;
	
	//Pens
	property CursorPenWidth : Integer Read _cursorWidth Write _cursorWidth;
	property AxisPenWidth : Integer Read _axisWidth Write _axisWidth;
	property MajorTickPenWidth : Integer Read _majorTickWidth Write _majorTickWidth;
	property MinorTickPenWidth : Integer Read _minorTickWidth Write _minorTickWidth;
	
	//Points
	property AxisOrigin : TPoint Read _axisOrigin Write _axisOrigin;
	
	//Axis Labels
	property XAxisLabel : String Read _xAxisLabel Write _xAxisLabel;
	Property YAxisLabel : String Read _yAxisLabel Write _yAxisLabel;
	
	//TScale
	property Scale : TScale Read _scale Write _scale;

	property StartTime : Real Read _start Write _start;
	
	property XMajorTicksPer : Integer Read _xMajorTicksPer Write _xMajorTicksPer;
	property XMinorTicksPer :Integer Read _xMinorTicksPer Write _xMinorTicksPer;
	property YMajorTicksPer : Integer Read _yMajorTicksPer Write _yMajorTicksPer;
	property YMinorTicksPer :Integer Read _yMinorTicksPer Write _yMinorTicksPer;  

        property DrawThickerDots : boolean Read _thickerDots Write _thickerDots;

	//Events
	property OnWhatsThis : TGraphQuery Read whatsThis Write whatsThis;

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Charith', [TPendulumGraph]);
end;

constructor TPendulumGraph.Create(AOwner: TComponent);
begin
	inherited Create(AOwner);
	//Create the bitmaps
	Self.Parent := (AOwner as TWincontrol);
	
	BufferBitmap := TBitmap.Create;
	CursorOverlayBitmap := TBitmap.Create;
	AxisOverlayBitmap := TBitmap.Create;
	DataOverlayBitmap := TBitmap.Create;
	
	//Default Pixel Format
	_defaultPixelFormat := pf16bit;
	
	//Set Pixel Formats
	BufferBitmap.PixelFormat := _defaultPixelFormat;
	CursorOverlayBitmap.PixelFormat := _defaultPixelFormat;
	AxisOverlayBitmap.PixelFormat := _defaultPixelFormat;
	DataOverlayBitmap.PixelFormat := _defaultPixelFormat;
	
	//Set Transparency on all but buffer
	CursorOverlayBitmap.TransparentColor := TRANSCOLOR;
	CursorOverlayBitmap.TransparentMode := tmFixed;
	CursorOverlayBitmap.Transparent := True;
	
	AxisOverlayBitmap.TransparentColor := TRANSCOLOR;
	AxisOverlayBitmap.TransparentMode := tmFixed;
	AxisOverlayBitmap.Transparent := True;
	
	DataOverlayBitmap.TransparentColor := TRANSCOLOR;
	DataOverlayBitmap.TransparentMode := tmFixed;
	DataOverlayBitmap.Transparent := True;

	//Set the initial colours
    BackgroundColor := clWhite;
	ForegroundColor:= clBlack;
	AxisColor := clGray;
	CursorColor := clRed;
	
	//Set the initial pen widths
	CursorPenWidth := 1;
	AxisPenWidth := 1;
	MajorTickPenWidth := 2;
	MinorTickPenWidth := 1;
	
	//Ticks
	XMajorTicksPer := 50;
	XMinorTicksPer := 10;
	
	YMajorTicksPer := 50;
	YMinorTicksPer := 10;
	  
	_scale := CreateScale(50, 50); //100 pixels per x,y graph unit
	_start := 0; //graph starts from time = 0
	
	_axisOrigin := Point(10, ClientRect.Bottom div 2); //Position the axes through the given point

	//Set preferences
	_displayAxes := true;
	_displayTicks := true;
	_displayScale := true;
        _thickerDots := false;
	
	//Create popup menu
	_popupMenu := TPopupMenu.Create(Self);
	
	_popupMenuItems[1] := TMenuItem.Create(Self);
	_popupMenuItems[1].Caption := '&Settings...';
	_popupMenuItems[1].OnClick := _menuShowSettings;
	_popupMenu.Items.Add(_popupMenuItems[1]);
	
	_popupMenuItems[2] := TMenuItem.Create(Self);
	_popupMenuItems[2].Caption := 'Re-&Initialise';
	_popupMenuItems[2].OnClick := _menuInitialise;
	_popupMenu.Items.Add(_popupMenuItems[2]);
	
	_popupMenuItems[3] := TMenuItem.Create(Self);
	_popupMenuItems[3].Caption := '&Reset X axis origin';
	_popupMenuItems[3].OnClick := _menuResetXAxis;
	_popupMenu.Items.Add(_popupMenuItems[3]);
	
	_popupMenuItems[4] := TMenuItem.Create(Self);
	_popupMenuItems[4].Caption := '-';
	_popupMenu.Items.Add(_popupMenuItems[4]);
	
	_popupMenuItems[5] := TMenuItem.Create(Self);
	_popupMenuItems[5].Caption := 'Display &Axes';
	_popupMenuItems[5].OnClick := _menuToggleAxes;
	_popupMenuItems[5].Checked := _displayAxes;
	_popupMenu.Items.Add(_popupMenuItems[5]);
	
	_popupMenuItems[6] := TMenuItem.Create(Self);
	_popupMenuItems[6].Caption := 'Display &Ticks';
	_popupMenuItems[6].OnClick := _menuToggleTicks;
	_popupMenuItems[6].Checked := _displayTicks;
	_popupMenu.Items.Add(_popupMenuItems[6]);

	_popupMenuItems[7] := TMenuItem.Create(Self);
	_popupMenuItems[7].Caption := 'Display Sca&le';
	_popupMenuItems[7].OnClick := _menuToggleScale;
	_popupMenuItems[7].Checked := _displayScale;
	_popupMenu.Items.Add(_popupMenuItems[7]);

        _popupMenuItems[10] := TMenuItem.Create(Self);
	_popupMenuItems[10].Caption := 'Draw Thicker Dots';
	_popupMenuItems[10].OnClick := _menuToggleDots;
	_popupMenuItems[10].Checked := _thickerDots;
	_popupMenu.Items.Add(_popupMenuItems[10]);

	_popupMenuItems[8] := TMenuItem.Create(Self);
	_popupMenuItems[8].Caption := '-';
	_popupMenu.Items.Add(_popupMenuItems[8]);
	
	_popupMenuItems[9] := TMenuItem.Create(Self);
	_popupMenuItems[9].Caption := '&What is this?';
	_popupMenuItems[9].OnClick := _menuWhatsThis;
	_popupMenu.Items.Add(_popupMenuItems[9]);
	
	Self.PopupMenu := _popupMenu;
	
    Self.Initialise;
end;

destructor TPendulumGraph.Destroy;
begin
	_ready := false;
	BufferBitmap.Free;
	CursorOverlayBitmap.Free;
	AxisOverlayBitmap.Free;
	DataOverlayBitmap.Free;
	_settingsWindow.Free;
	inherited Destroy;
end;

//Reset Drawing Tools
//-------------------
//Resets each bitmaps default pen widths, pen colors, brush colors and styles
procedure TPendulumGraph._resetDrawingTools;
begin
	//Our buffer bitmap needs only a background color
	With BufferBitmap do
	begin
		Canvas.Brush.Color := _backgroundColor;
		Canvas.Brush.Style := bsSolid;
	end;
	
	//Cursor overlay needs the transparent background color set
	//pen color is the cursor color, pen width the cursor pen width
	With CursorOverlayBitmap do
	begin
		Canvas.Brush.Style := bsSolid;
        Canvas.Brush.Color := TRANSCOLOR;
		Canvas.Pen.Color := _cursorColor;
		Canvas.Pen.Width := _cursorWidth;
		Canvas.Pen.Style := psDash; //Dashed cursor?
	end;
	
	//Axis overlay behaves simillar to the above
	With AxisOverlayBitmap do
	begin
		Canvas.Brush.Style := bsSolid;
		Canvas.Brush.Color := TRANSCOLOR;
		Canvas.Pen.Color := _axisColor;
		Canvas.Pen.Width := _axisWidth;
		Canvas.Pen.Style := psSolid;
		
		Canvas.Font.Color := _axisColor;
	end;
	
	//Data overlay just sets pixels or draws lines
	With DataOverlayBitmap do
	begin
		Canvas.Pen.Color := _foregroundColor;
	end;
end;

// Readjust Sizes
procedure TPendulumGraph._readjustSizes;
var
	oldSize : TSize;
	ratioX, ratioY : real;
begin
	//Collect the old sizes for scaling
	oldSize.cx := BufferBitmap.Width;
	oldSize.cy := BufferBitmap.Height;
	
	//Begin by setting the bounds of each bitmap
	BufferBitmap.Height := ClientRect.Bottom;
	BufferBitmap.Width := ClientRect.Right;
	
	CursorOverlayBitmap.Height := ClientRect.Bottom;
	CursorOverlayBitmap.Width := ClientRect.Right;
	
	AxisOverlayBitmap.Height := ClientRect.Bottom;
	AxisOverlayBitmap.Width := ClientRect.Right;
	
	DataOverlayBitmap.Height := ClientRect.Bottom;
	DataOverlayBitmap.Width := ClientRect.Right;
	
	//Find the ratio by which the scaling took place
	if (oldSize.cx <> 0) then
	ratioX := ClientRect.Right / oldSize.cx
	else
	ratioX := 1;
	
	if (oldSize.cy <> 0) then
	ratioY := ClientRect.Bottom / oldSize.cy
	else
	ratioY := 1;
	
	//Our new scale is the old scale multiplied by this ratio
	_scale := CreateScale(ratioX*_scale.x, ratioY*_scale.y);
	
	//Our origin x and y co-ords are scaled by the same ratio
	_axisOrigin.x := round(_axisOrigin.x*ratioX);
	_axisOrigin.y := round(_axisOrigin.y*ratioY);
	
	//TODO:
	//Call initialisation code for each layer
	//Call initialisation of axes
	_AxisInitialise;
	
end;

Procedure TPendulumGraph.Resize;
begin
	inherited Resize;
	if _ready then
	begin
	_readjustSizes;
	Initialise;
	end;
end;

procedure TPendulumGraph._AxisInitialise;
var
	xMajorTickCount, xMinorTickCount, yMajorTickCount, yMinorTickCount : integer;
	i: integer;
	tout : string;
begin
	_resetDrawingTools;
	
	
	
	With AxisOverlayBitmap do
	begin
                
		Canvas.FillRect(Self.ClientRect);
		Canvas.Pen.Width := Self.AxisPenWidth;
		Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y);
		Canvas.LineTo( ClientRect.Right, _axisOrigin.y);
			
		Canvas.MoveTo(_axisOrigin.x, 0);
		Canvas.LineTo(_axisOrigin.x, ClientRect.Bottom);
	end;
	
	
	//Scale is graph units per pixel
	
	
	
	
	With AxisOverlayBitmap do
    begin
	Canvas.Brush.Style := bsClear;
	//X axis ticks
	//X axis units are seconds
	if _displayTicks then
	begin
	//Major ticks
	//Get the number of ticks to draw
	
    Canvas.Pen.Width := MajorTickPenWidth; //Set the pen width
	Canvas.Pen.Color := AxisColor; //Set the axis color
	
	xMajorTickCount := trunc((AxisOverlayBitmap.Width -_axisOrigin.x) / _xMajorTicksPer) - 1; //Get the number of major ticks to draw
	//For loop to draw major ticks
	for i := 1 to xMajorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x + i*_xMajorTicksPer, _axisOrigin.y);
		Canvas.LineTo(_axisOrigin.x + i*_xMajorTicksPer, _axisOrigin.y + 5);
		if _displayScale then
		begin
		tout := formatfloat('0.###', _start + i*xMajorTicksPer/_scale.x);
		Canvas.TextOut(_axisOrigin.x + i*_xMajorTicksPer - (Canvas.TextWidth(tout) div 2), _axisOrigin.y + 5, tout);
		end;
	end;
	
	//Minor Ticks
	Canvas.Pen.Width := MinorTickPenWidth;
	Canvas.Pen.Color := AxisColor;

	xMinorTickCount := trunc((AxisOverlayBitmap.Width -_axisOrigin.x) / _xMinorTicksPer);
	for i := 1 to xMinorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x + i*_xMinorTicksPer, _axisOrigin.y);
		Canvas.LineTo(_axisOrigin.x + i*_xMinorTicksPer, _axisOrigin.y + 5);
	end;
	
	//Y axis ticks
	
	//Draw ticks for bottom half of y axis (negative y's)	
	
	//Major Ticks
	Canvas.Pen.Width := MajorTickPenWidth;
	Canvas.Pen.Color := AxisColor;
	
	
	yMajorTickCount := trunc((AxisOverlayBitmap.Height -_axisOrigin.y) / _yMajorTicksPer);
	for i := 1 to yMajorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y  + i*_yMajorTicksPer);
		Canvas.LineTo(_axisOrigin.x - 5, _axisOrigin.y  + i*_yMajorTicksPer);
		if _displayScale then
		begin
		tout := formatfloat('0.###', -i*yMajorTicksPer/_scale.y);
		Canvas.TextOut(_axisOrigin.x - (Canvas.TextWidth(tout)) - 10, _axisOrigin.y + i*_yMajorTicksPer - (Canvas.TextHeight(tout) div 2), tout);
		end;
	end;
	
	//Minor Ticks
	Canvas.Pen.Width := MinorTickPenWidth;
	Canvas.Pen.Color := AxisColor;

	yMinorTickCount := trunc((AxisOverlayBitmap.Height -_axisOrigin.y) / _yMinorTicksPer);
	for i := 1 to yMinorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y  + i*_yMinorTicksPer);
		Canvas.LineTo(_axisOrigin.x - 5, _axisOrigin.y  + i*_yMinorTicksPer);
	end;
	
	//Draw ticks for top half of y axis (positive y's)
	Canvas.Pen.Width := MajorTickPenWidth;
	Canvas.Pen.Color := AxisColor;
	
	//Major Ticks
	yMajorTickCount := trunc((_axisOrigin.y) / _yMajorTicksPer);
	for i := 1 to yMajorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y  - i*_yMajorTicksPer);
		Canvas.LineTo(_axisOrigin.x - 5, _axisOrigin.y  - i*_yMajorTicksPer);
		if _displayScale then
		begin
			tout := formatfloat('0.###', i*yMajorTicksPer/_scale.y);
			Canvas.TextOut(_axisOrigin.x - (Canvas.TextWidth(tout)) - 10, _axisOrigin.y - i*_yMajorTicksPer - (Canvas.TextHeight(tout) div 2), tout);
		end;
	end;
	
	//Minor Ticks
	Canvas.Pen.Width := MinorTickPenWidth;
	Canvas.Pen.Color := AxisColor;

	yMinorTickCount := trunc((_axisOrigin.y) / _yMinorTicksPer);
	for i := 1 to yMinorTickCount do
	begin
		//Move the pen to the xposition on the axis
		Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y  - i*_yMinorTicksPer);
		Canvas.LineTo(_axisOrigin.x - 5, _axisOrigin.y  - i*_yMinorTicksPer);
	end;
	
	//Do something special at the origin;

	Canvas.Pen.Width := MajorTickPenWidth;
	Canvas.MoveTo(_axisOrigin.x - 5, _axisOrigin.y);
	Canvas.LineTo(_axisOrigin.x + 5, _axisOrigin.y);
	
	Canvas.MoveTo(_axisOrigin.x, _axisOrigin.y - 5);
	Canvas.LineTo(_axisOrigin.x, _axisOrigin.y + 5);
		if _displayScale then
		begin
			tout := '0 , '+formatfloat('0.#', _start);
			Canvas.TextOut(_axisOrigin.x - Canvas.TextWidth(tout) - 6, _axisOrigin.y - (Canvas.TextHeight(tout) div 2), tout);
		end;
	end;
	//Axis Labels
	tout := _xAxisLabel;
    Canvas.Font.Style := [fsBold];
	Canvas.TextOut(Width - Canvas.TextWidth(tout) - 10, _axisOrigin.y + 5, tout);

	tout := _yAxisLabel;
	Canvas.TextOut(_axisOrigin.x + 5, 5, tout);
	Canvas.Font.Style := [];

	end;
	
end;

procedure TPendulumGraph._drawCursor(x, y : integer);
begin
	_resetDrawingTools;

	With CursorOverlayBitmap do
	begin
		Canvas.FillRect(ClientRect);
		
		Canvas.MoveTo(x, 0);
		Canvas.LineTo(x, ClientRect.Bottom);

		Canvas.MoveTo(0, y);
		Canvas.LineTo(ClientRect.Right, y);
	end;


end;

procedure TPendulumGraph.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
	//if ssLeft in Shift then
	//_hintWindow.ActivateHint(Rect(10,10,50,50),'hello');
        //if ssLeft in Shift then
	//_drawCursor( x, y);
end;


procedure TPendulumGraph.Paint;
begin
	inherited Paint;
	//_readjustSizes;
	
	With BufferBitmap do
	begin
    Canvas.Brush.Color := BackgroundColor;
	Canvas.FillRect(ClientRect);
	end;
	
	//
	//BufferBitmap.Canvas.Draw(0,0,CursorOverlayBitmap);
	if _displayAxes then
	BufferBitmap.Canvas.Draw(0,0,AxisOverlayBitmap);
	BufferBitmap.Canvas.Draw(0,0,DataOverlayBitmap);
	Canvas.Draw(0,0,BufferBitmap);

end;

procedure TPendulumGraph.Initialise;
begin
	_ready := true;
	
	if (_autoScale) and (_maxAmplitude <> 0) then
	begin
		_scale.y := _axisOrigin.y/_maxAmplitude;
		_maxAmplitude := 1;
	end;
	
    _readjustSizes; //Readjust the size of the bitmaps
	
	With BufferBitmap do
	begin
    Canvas.Brush.Color := BackgroundColor;
	Canvas.FillRect(ClientRect);
	end;
	
	With DataOverlayBitmap do
	begin
	Canvas.Brush.Color :=TRANSCOLOR;
	Canvas.FillRect(ClientRect);
	end;
	
end;


{
Draw Point
----------
Given a time and amplitude, it translates that onto on screen pixel
co-ordinates and drops a point. If the point exceeds the bounds of
our view, it will shift the view as needed.
}
procedure TPendulumGraph.DrawPointWithColor(time, amplitude: real; color : TColor);
var x, y : integer;
begin
        _resetDrawingTools;
		
		//Record the maximum amplitude
		_maxAmplitude := max(_maxAmplitude, amplitude);
		
		//Calculate the x position in pixels
		
		//Check to see if we're out of range, if so, call Initialise
		if ((time-_start) < 0) or ((time-_start) > ((DataOverlayBitmap.Width-_axisOrigin.x)/_scale.x)) then
		begin
		_start := time;
		Self.Initialise;
		end;
		
		x := round((time - _start)*_scale.x) + _axisOrigin.x;
		
		//Calculate the y position in pixels
		
		if amplitude = 0 then
		y := _axisOrigin.y
		else
		y := _axisOrigin.y - round(_scale.y*amplitude);

		
        With DataOverlayBitmap do
        begin
        Canvas.Pixels[x,y] := color;
        // thickerDots = true would surround the above pixel x, y with aditional pixels
        //      *
        //    * * *
        //      *
        // Where the center * is (x, y)
        if _thickerDots then
        begin
            Canvas.Pixels[x-1,y] := color;
            Canvas.Pixels[x+1,y] := color;
            Canvas.Pixels[x,y+1] := color;
            Canvas.Pixels[x,y-1] := color;
        end;
        end;
end;

procedure TPendulumGraph.DrawPoint(time, amplitude: real);
begin
	DrawPointWithColor(time, amplitude, _foregroundColor);
end;


//Set scale
//---------
//Sets the scale of the axes (call initialise immediately after)
procedure TPendulumGraph.SetScale(x, y : real);
begin
	_scale := CreateScale(x, y);
end;


//Set origin
//----------
//Sets the origin of the axes
procedure TPendulumGraph.SetOrigin(x, y : integer);
begin
	_axisOrigin.x := x;
	_axisOrigin.y := y;
end;

//Show Settings
//-------------
//Shows the settings window for the pendulum graph view
procedure TPendulumGraph.ShowSettings;
begin
	if _settingsWindow = nil then 
	_settingsWindow := TGraphSettings.CreateWithSettings(Self, _backgroundColor, _foregroundColor, _axisColor, _cursorColor, _axisOrigin, _scale, _xMajorTicksPer, _xMinorTicksPer, _autoScale);
	
	_settingsWindow.InitialiseMethod := Initialise;
	_settingsWindow.UpdateBoxes;
	_settingsWindow.Show;
	
end;

//Menu Handler : ShowSettings
//---------------------------
//Shows the settings window for the pendulum graph view
procedure TPendulumGraph._menuShowSettings(Sender : TObject);
begin
	ShowSettings;
end;

//Menu Handler : Initialise
//-------------------------
//Calls the pendulum graph views initialise function
procedure TPendulumGraph._menuInitialise(Sender : TObject);
begin
	Initialise;
end;

//Menu Handler : ResetXAxis
//-------------------------
//Resets the X axis to be centered vertically in the window
procedure TPendulumGraph._menuResetXAxis(Sender : TObject);
begin
	_axisOrigin.y := ClientRect.Bottom div 2;
	Initialise;
end;

//Menu Handler : Toggle Axis
procedure TPendulumGraph._menuToggleAxes(Sender : TObject);
begin
	_displayAxes := not _displayAxes;
	_popupMenuItems[5].Checked := _displayAxes;
	
end;

//Menu Handler : Toggle Ticks
procedure TPendulumGraph._menuToggleTicks(Sender : TObject);
begin
	_displayTicks := not _displayTicks  ;
	_popupMenuItems[6].Checked := _displayTicks;
	_AxisInitialise;
end;

//Menu Handler : Toggle Scale
procedure TPendulumGraph._menuToggleScale(Sender : TObject);
begin
	_displayScale := not _displayScale;
	_popupMenuItems[7].Checked := _displayScale;
	_AxisInitialise;
end;

//Menu Handler : Thicker Dots
procedure TPendulumGraph._menuToggleDots(Sender : TObject);
begin
        _thickerDots := not _thickerDots;
        _popupMenuItems[10].Checked := _thickerDots;
end;

procedure TPendulumGraph._menuWhatsThis(Sender : TObject);
begin
        if Assigned(whatsThis) then whatsThis(Self);
end;

end.
